﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Text;
using System.Threading.Tasks;
using TestEntity;

namespace TestEntity
{
    public class Student
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public int SchoolId { get; set; }
    }
    class Program
    {
        static void Main(string[] args)
        {
            Demo1();
            Demo2();
            Demo3();
            Demo4() ;
            Demo5();
            Mapper<Student>();
            var list = new List<Student>() { new Student() { Id = 1, Name = "x" }, new Student() { Id = 2, Name = "2" } };
            var list3 = CopyObject(list);
            foreach (var item in list)
            {
                item.Name = null;
            }
        }
        public static List<Student> CopyObject(List<Student> list1)
        {
            List<Student> list = new List<Student>();
            List<Student>.Enumerator enumerator = list1.GetEnumerator();
            while (enumerator.MoveNext())
            {
                Student current = enumerator.Current;
                Student item = new Student
                {
                    Id = current.Id,
                    Name = current.Name
                };
                list.Add(item);
            }
            return list;
            enumerator.Dispose();
            return list;
        }

        private static void Mapper<T>()
        {
            //创建类
            string assemblyNameStr = "SugarMapper";
            AssemblyName assemblyName = new AssemblyName(assemblyNameStr);
            AssemblyBuilder assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.RunAndSave);
            ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule(assemblyNameStr, assemblyNameStr + ".dll");
            TypeBuilder typeBuilder = moduleBuilder.DefineType(assemblyNameStr, TypeAttributes.Public);
            var typeList = typeof(List<T>);
            var typeItem = typeof(T);
            var typeEnumerator = typeof(List<T>.Enumerator);
            //创建方法
            MethodBuilder showMethod = typeBuilder.DefineMethod("CopyObject", MethodAttributes.Public | MethodAttributes.Static, typeof(List<T>)/*无返回值设为null*/, new Type[] { typeof(List<T>) }/*参数类型*/);
            ILGenerator il = showMethod.GetILGenerator();
          
            LocalBuilder result = il.DeclareLocal(typeList);//0
            LocalBuilder enumerator = il.DeclareLocal(typeEnumerator);//1
            LocalBuilder enumeratorItem = il.DeclareLocal(typeItem);//2
            LocalBuilder addItem = il.DeclareLocal(typeItem);//3
     

            Label Brs1 = il.DefineLabel();
            Label BrtrueS1 = il.DefineLabel();
            Label LeaveS1 = il.DefineLabel();
            Label Brs2 = il.DefineLabel();
         
            il.Emit(OpCodes.Nop);
            il.Emit(OpCodes.Newobj, typeList.GetConstructor(Type.EmptyTypes));
            il.Emit(OpCodes.Stloc, result);
            il.Emit(OpCodes.Nop);

            il.Emit(OpCodes.Ldarg_0);//参数加载到内存执行循环
            il.Emit(OpCodes.Callvirt, typeList.GetMethod("GetEnumerator"));
            il.Emit(OpCodes.Stloc, enumerator);
            il.Emit(OpCodes.Br_S, Brs1);
            il.MarkLabel(BrtrueS1);//foreach{
            il.Emit(OpCodes.Ldloca_S, enumerator);
            il.Emit(OpCodes.Call, typeEnumerator.GetMethod("get_Current"));
            il.Emit(OpCodes.Stloc, enumeratorItem);
            il.Emit(OpCodes.Nop);
            il.Emit(OpCodes.Newobj, typeItem.GetConstructor(Type.EmptyTypes));
            il.Emit(OpCodes.Stloc, addItem);

            typeItem.GetProperties().Cast<PropertyInfo>().ToList().ForEach(it =>
            {
                var isValueType = it.PropertyType.IsValueType&& it.PropertyType!=typeof(string);
                if (isValueType)
                {
                    il.Emit(OpCodes.Nop);
                    il.Emit(OpCodes.Ldloc, addItem);
                    il.Emit(OpCodes.Ldloc, enumeratorItem);
                    il.Emit(OpCodes.Callvirt, typeItem.GetMethod("get_" + it.Name));
                    il.Emit(OpCodes.Callvirt, typeItem.GetMethod("set_" + it.Name));
                }
                else {


                }
            });

            il.Emit(OpCodes.Nop);
            il.Emit(OpCodes.Ldloc, result);
            il.Emit(OpCodes.Ldloc, addItem);
            il.Emit(OpCodes.Callvirt, typeList.GetMethod("Add"));
            il.Emit(OpCodes.Nop);
            il.Emit(OpCodes.Nop);
            il.MarkLabel(Brs1);//new{
            il.Emit(OpCodes.Ldloca_S, enumerator);
            il.Emit(OpCodes.Call, typeEnumerator.GetMethod("MoveNext"));
            il.Emit(OpCodes.Brtrue_S, BrtrueS1);
            il.Emit(OpCodes.Leave_S, LeaveS1);
            il.Emit(OpCodes.Ldloca_S, enumerator);
            il.Emit(OpCodes.Constrained, typeEnumerator);
            il.Emit(OpCodes.Callvirt, typeof(System.IDisposable).GetMethod("Dispose"));
            il.Emit(OpCodes.Nop);
            il.Emit(OpCodes.Endfinally);
            il.MarkLabel(LeaveS1);//}end
            il.Emit(OpCodes.Ldloc_0);
            il.Emit(OpCodes.Stloc_S,result);
            il.Emit(OpCodes.Br_S, Brs2);
            il.MarkLabel(Brs2);//}foreach
            il.Emit(OpCodes.Ldloc_S, result);
            il.Emit(OpCodes.Ret);
            Type t = typeBuilder.CreateType();
            assemblyBuilder.Save(assemblyNameStr + ".dll");
        }

        private static void Demo5()
        {
            //创建类
            string assemblyNameStr = "Test5";
            AssemblyName assemblyName = new AssemblyName(assemblyNameStr);
            AssemblyBuilder assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.RunAndSave);
            ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule(assemblyNameStr, assemblyNameStr + ".dll");
            TypeBuilder typeBuilder = moduleBuilder.DefineType(assemblyNameStr, TypeAttributes.Public);
            MethodBuilder methodBuilder = typeBuilder.DefineMethod("ForeachMethod", MethodAttributes.Public | MethodAttributes.Static, typeof(Int32), new Type[] { typeof(List<Student>) });
            ILGenerator methodIL = methodBuilder.GetILGenerator();

            //用来保存求和结果的局部变量
            LocalBuilder sum = methodIL.DeclareLocal(typeof(Int32));
            //foreach 中的 int i 
            LocalBuilder i = methodIL.DeclareLocal(typeof(Student));
            //用来保存传入的数组
            LocalBuilder ints = methodIL.DeclareLocal(typeof(List<Student>));
            //数组循环用临时变量
            LocalBuilder index = methodIL.DeclareLocal(typeof(Int32));

            Label compareLabel = methodIL.DefineLabel();
            Label enterLoopLabel = methodIL.DefineLabel();

            //int sum = 0;
            methodIL.Emit(OpCodes.Ldc_I4_0);
            methodIL.Emit(OpCodes.Stloc, sum);
            //ints = ints
            methodIL.Emit(OpCodes.Ldarg_0);
            methodIL.Emit(OpCodes.Stloc, ints);
            //int index = 0
            methodIL.Emit(OpCodes.Ldc_I4_0);
            methodIL.Emit(OpCodes.Stloc, index);
            methodIL.Emit(OpCodes.Br, compareLabel);

            //定义一个标签，表示从下面开始进入循环体
            methodIL.MarkLabel(enterLoopLabel);
            //其中Ldelem_I4用来加载一个数组中的Int32类型的元素
            //加载 i = ints[index]
            methodIL.Emit(OpCodes.Ldloc, ints);
            methodIL.Emit(OpCodes.Ldloc, index);
            methodIL.Emit(OpCodes.Ldelem_I4);
            methodIL.Emit(OpCodes.Stloc, i);
           

            //index++
            methodIL.Emit(OpCodes.Ldloc, index);
            methodIL.Emit(OpCodes.Ldc_I4_1);
            methodIL.Emit(OpCodes.Add);
            methodIL.Emit(OpCodes.Stloc, index);

            //定义一个标签，表示从下面开始进入循环的比较
            methodIL.MarkLabel(compareLabel);
            //index < ints.Length
            methodIL.Emit(OpCodes.Ldloc, index);
            methodIL.Emit(OpCodes.Ldloc, ints);
            methodIL.Emit(OpCodes.Ldlen);
            methodIL.Emit(OpCodes.Conv_I4);
            methodIL.Emit(OpCodes.Clt);
            methodIL.Emit(OpCodes.Brtrue_S, enterLoopLabel);

            //return sum;
            methodIL.Emit(OpCodes.Ldloc, sum);
            methodIL.Emit(OpCodes.Ret);
            Type t = typeBuilder.CreateType();
            assemblyBuilder.Save(assemblyNameStr + ".dll");
        }

        private static void Demo4()
        {
            //创建类
            string assemblyNameStr = "Test4";
            AssemblyName assemblyName = new AssemblyName(assemblyNameStr);
            AssemblyBuilder assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.RunAndSave);
            ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule(assemblyNameStr, assemblyNameStr + ".dll");
            TypeBuilder typeBuilder = moduleBuilder.DefineType(assemblyNameStr, TypeAttributes.Public);
            MethodBuilder methodBuilder = typeBuilder.DefineMethod("ForeachMethod", MethodAttributes.Public | MethodAttributes.Static, typeof(Int32), new Type[] { typeof(Int32[]) });
            ILGenerator methodIL = methodBuilder.GetILGenerator();

            //用来保存求和结果的局部变量
            LocalBuilder sum = methodIL.DeclareLocal(typeof(Int32));
            //foreach 中的 int i 
            LocalBuilder i = methodIL.DeclareLocal(typeof(Int32));
            //用来保存传入的数组
            LocalBuilder ints = methodIL.DeclareLocal(typeof(Int32[]));
            //数组循环用临时变量
            LocalBuilder index = methodIL.DeclareLocal(typeof(Int32));

            Label compareLabel = methodIL.DefineLabel();
            Label enterLoopLabel = methodIL.DefineLabel();

            //int sum = 0;
            methodIL.Emit(OpCodes.Ldc_I4_0);
            methodIL.Emit(OpCodes.Stloc,sum);
            //ints = ints
            methodIL.Emit(OpCodes.Ldarg_0);
            methodIL.Emit(OpCodes.Stloc,ints);
            //int index = 0
            methodIL.Emit(OpCodes.Ldc_I4_0);
            methodIL.Emit(OpCodes.Stloc,index);
            methodIL.Emit(OpCodes.Br, compareLabel);

            //定义一个标签，表示从下面开始进入循环体
            methodIL.MarkLabel(enterLoopLabel);
            //其中Ldelem_I4用来加载一个数组中的Int32类型的元素
            //加载 i = ints[index]
            methodIL.Emit(OpCodes.Ldloc,ints);
            methodIL.Emit(OpCodes.Ldloc,index);
            methodIL.Emit(OpCodes.Ldelem_I4);
            methodIL.Emit(OpCodes.Stloc,i);
            //sum += i;
            methodIL.Emit(OpCodes.Ldloc,sum);
            methodIL.Emit(OpCodes.Ldloc,i);
            methodIL.Emit(OpCodes.Add);
            methodIL.Emit(OpCodes.Stloc,sum);

            //index++
            methodIL.Emit(OpCodes.Ldloc,index);
            methodIL.Emit(OpCodes.Ldc_I4_1);
            methodIL.Emit(OpCodes.Add);
            methodIL.Emit(OpCodes.Stloc,index);

            //定义一个标签，表示从下面开始进入循环的比较
            methodIL.MarkLabel(compareLabel);
            //index < ints.Length
            methodIL.Emit(OpCodes.Ldloc,index);
            methodIL.Emit(OpCodes.Ldloc,ints);
            methodIL.Emit(OpCodes.Ldlen);
            methodIL.Emit(OpCodes.Conv_I4);
            methodIL.Emit(OpCodes.Clt);
            methodIL.Emit(OpCodes.Brtrue_S, enterLoopLabel);

            //return sum;
            methodIL.Emit(OpCodes.Ldloc,sum);
            methodIL.Emit(OpCodes.Ret);
            Type t = typeBuilder.CreateType();
            assemblyBuilder.Save(assemblyNameStr + ".dll");
        }

        private static void Demo3()
        {
            //创建类
            string assemblyNameStr = "Test3";
            AssemblyName assemblyName = new AssemblyName(assemblyNameStr);
            AssemblyBuilder assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.RunAndSave);
            ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule(assemblyNameStr, assemblyNameStr + ".dll");
            TypeBuilder typeBuilder = moduleBuilder.DefineType(assemblyNameStr, TypeAttributes.Public);

            //创建方法
            MethodBuilder showMethod = typeBuilder.DefineMethod("Mapper", MethodAttributes.Public | MethodAttributes.Static, typeof(List<Student>)/*无返回值设为null*/, new Type[] { typeof(List<Student>) }/*参数类型*/);

            ILGenerator il = showMethod.GetILGenerator();
            il.Emit(OpCodes.Ldarg_0);//将参数变量初始化


            var result= il.DeclareLocal(typeof(List<Student>));
            il.Emit(OpCodes.Newobj, typeof(List<Student>).GetConstructor(Type.EmptyTypes));
            il.Emit(OpCodes.Stloc,result);


            il.Emit(OpCodes.Ldloc,result);
            il.Emit(OpCodes.Ret);//返回lbl
            Type t = typeBuilder.CreateType();
            assemblyBuilder.Save(assemblyNameStr + ".dll");
        }


        private static void Demo2()
        {
            //创建类
            string assemblyNameStr = "Test2";
            AssemblyName assemblyName = new AssemblyName(assemblyNameStr);
            AssemblyBuilder assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.RunAndSave);
            ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule(assemblyNameStr, assemblyNameStr + ".dll");
            TypeBuilder typeBuilder = moduleBuilder.DefineType(assemblyNameStr, TypeAttributes.Public);

            //创建方法
            MethodBuilder showMethod = typeBuilder.DefineMethod("GetFormatString", MethodAttributes.Public | MethodAttributes.Static, typeof(string)/*无返回值设为null*/, new Type[] { typeof(int), typeof(string) }/*参数类型*/);

            ILGenerator il = showMethod.GetILGenerator();
            il.Emit(OpCodes.Ldstr, "姓名：{1} 年龄：{0}");
            //静态方法参数索引从0开始
            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Ldarg_1);
            il.Emit(OpCodes.Call, typeof(string).GetMethod("Format", new Type[] { typeof(string), typeof(int), typeof(string) }));
            //il.Emit(OpCodes.Pop); //如果是不需要返回的方法加恢复注释部分
            il.Emit(OpCodes.Ret);
            Type t = typeBuilder.CreateType();
            assemblyBuilder.Save(assemblyNameStr + ".dll");
        }

        private static void Demo1()
        {
            #region
            var asmName = new AssemblyName("Test");
            var asmBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(asmName, AssemblyBuilderAccess.RunAndSave);//创建程序集
            var mdlBldr = asmBuilder.DefineDynamicModule("Test", "Test.dll");//定义模块
            var typeBldr = mdlBldr.DefineType("ILTest", TypeAttributes.Public);//定义类
            var methodBldr = typeBldr.DefineMethod("Sum", MethodAttributes.Public, typeof(int), null);//定义方法
            var il = methodBldr.GetILGenerator();//获取il生成器
            #endregion

            //IL注册变量
            il.DeclareLocal(typeof(int));
            il.DeclareLocal(typeof(int));
            il.DeclareLocal(typeof(int));
            var i = il.DeclareLocal(typeof(int));

            Label lbl = il.DefineLabel();


            il.Emit(OpCodes.Ldc_I4_1);//变量1=1
            il.Emit(OpCodes.Stloc_0);

            il.Emit(OpCodes.Ldc_I4_2);//变量2=2
            il.Emit(OpCodes.Stloc_1);

            il.Emit(OpCodes.Ldc_I4_4);//变量3=4
            il.Emit(OpCodes.Stloc_2);

            il.Emit(OpCodes.Ldloc_0);
            il.Emit(OpCodes.Ldloc_1);
            il.Emit(OpCodes.Add);//变量1+变量2
            il.Emit(OpCodes.Ldloc_2);
            il.Emit(OpCodes.Add);//在加变量3


            il.Emit(OpCodes.Stloc, i);//将lbl变成局部变量
            il.Emit(OpCodes.Br_S, lbl);
            il.MarkLabel(lbl);
            il.Emit(OpCodes.Ldloc, i);
            il.Emit(OpCodes.Ret);//返回lbl

            typeBldr.CreateType();
            asmBuilder.Save("Test.dll");//方便反编译 看代码写的对不对

            //生成的方法
            //  public int Sum()
            // {
            //  int num = 1;
            //  int num2 = 2;
            //  int num3 = 4;
            //  return ((num + num2) + num3);
            //}

        }
 
    }
}
